# ===============================
# author: Paulo Trigo Silva (PTS)
# since: MAI.2010
# version: v03
# ===============================
# v02: inclui "principio do mundo fechado"
# ver: "Does Pellet support closed world reasoning?"
# em: http://clarkparsia.com/pellet/faq/closed-world/

#______________________________________________________________________________
# Baseado nos exemplos em:
# http://owlapi.sourceforge.net/documentation.html

#______________________________________________________________________________
# Python
import os
from desenhadorOntologia import DesenhadorOntologia, pathToStringURI, gravar

#______________________________________________________________________________
# Java
from org.mindswap.pellet.owlapi import Reasoner
from org.mindswap.pellet import PelletOptions
from org.semanticweb.owl.inference import OWLReasonerAdapter
from org.semanticweb.owl.util import DLExpressivityChecker
from org.semanticweb.owl.util import InferredOntologyGenerator, InferredSubClassAxiomGenerator, InferredClassAssertionAxiomGenerator, InferredEquivalentClassAxiomGenerator
from org.semanticweb.owl.util import OWLEntityCollector
from org.semanticweb.owl.model import OWLClass
from org.semanticweb.owl.model import OWLDescription 
from java.util import Collections
from java.net import URI

#______________________________________________________________________________
class ExecutorInferencia( DesenhadorOntologia ):
   def __init__( self, strPhysicalURI, strOntologyURI="" ):
      DesenhadorOntologia.__init__( self, strPhysicalURI, strOntologyURI )
      # We need to create an instance of Reasoner.
      # Reasoner provides the basic query functionality that we need,
      # for example the ability obtain the subclasses of a class etc.
      # We will use pellet, but we could also use FaCT++.
      # Pellet requires the Pellet libraries  (pellet.jar, aterm-java-x.x.jar, etc) and the
      # XSD libraries that are bundled with pellet (xsdlib.jar and relaxngDatatype.jar)
      # (make sure these jars are on the classpath)
      self.reasoner = Reasoner( self.manager )
      PelletOptions.USE_UNIQUE_NAME_ASSUMPTION = True
      print self.reasoner


   def carregar( self ):
      # We now need to load some ontologies into the reasoner.
      # This is typically the imports closure of an ontology that we're interested in.
      # Note that no assumptions are made about the dependency of one ontology on another ontology.
      # This means that, e.g., if we loaded just the pizza ontology (using a singleton set)
      # then any imported ontologies would not automatically be loaded.
      # Obtain and load the imports closure of the ontology and then classify the ontology
      self.importsClosure = self.manager.getImportsClosure( self.ontology )
      self.reasoner.loadOntologies( self.importsClosure )
      # Ou, se nao quiser carregar as ontologias importadas de "self.ontology", entao:
      # descomentar a proxima linha e comentar as duas linhas de codigo anteriores
      #self.reasoner.loadOntology( self.ontology )
      # Classify the ontology
      self.reasoner.classify()   


   def actualizar( self ):
      self.reasoner.refresh()


   def obterExpressividadeDL( self ):
      # We can examine the expressivity of our ontology
      # (some reasoners do not support the full expressivity of OWL)
      checker = DLExpressivityChecker( self.importsClosure )
      expressivity = checker.getDescriptionLogicName()
      return expressivity


   def eConsistente( self ):
      # We can determine if the ontology is actually consistent.
      # (if an ontology is inconsistent then owl:Thing is equivalent to owl:Nothing;
      #  i.e. there can't be any models of the ontology)
      consistent = self.reasoner.isConsistent( self.ontology );
      return consistent


   def inferirDescendentes( self, concept, flattenResult=False ):
      # Now we want to query the reasoner for all descendants of concept
      # Get a reference to the class classOWL
      # (por omissao uma string e' transformada numa classe OWL)
      if type( concept ) == type( 'str' ): concept = self.obterClasse( concept )
      if not isinstance( concept, OWLDescription ): print "\n-- Erro: inferirDescendentes --\n"
      # Now use the reasoner to obtain the subclasses of classReference.
      # Note the reasoner returns a set of sets.
      # Each set represents a subclass of the classReference where
      # the classes in the set represent equivalence classes.
      # For example, if we asked for the subclasses of A and got back {{B, C}, {D}}
      # then A would have essentially two subclasses:
      # - one of these subclasses would be equivalent to the class D, and
      # - the other subclass would be the class that was equivalent to class B and class C.
      subClassSets = self.reasoner.getDescendantClasses( concept )
      if flattenResult:
         # In this case we will flatten this set of sets
         # (e.g, because we don't care about the equivalences)
         return OWLReasonerAdapter.flattenSetOfSets( subClassSets )
      return subClassSets


   def inferirInstancias( self, concept, onlyDirectInstances=False ):
      # (por omissao uma string e' transformada numa classe OWL)
      if type( concept ) == type( 'str' ): concept = self.obterClasse( concept )
      if not isinstance( concept, OWLDescription ): print "\n-- Erro: inferirInstancias --\n"
      return self.reasoner.getIndividuals( concept, onlyDirectInstances )


   def gerarOntologiaComConhecimentoInferido( self, strNewPhysicalURI, strNewOntologyURI="",
                                              axiomGenerators=[ InferredSubClassAxiomGenerator() ] ):
      # To generate an inferred ontology we use implementations of inferred axiom generators
      # to generate the parts of the ontology we want (e.g. subclass axioms, equivalent classes
      # axioms, class assertion axiom etc. - see org.semanticweb.owl.util package for more implementations).  
      # Our list of inferred axiom generators is set up in axiomGenerators parameter
      axiomGenerators=[ InferredSubClassAxiomGenerator(), InferredClassAssertionAxiomGenerator(), InferredEquivalentClassAxiomGenerator() ]
      iog = InferredOntologyGenerator( self.reasoner, axiomGenerators )
      # Criar a nova ontologia 'a qual adicionar o conhecimento inferido (da ontologia original)
      # Put the inferred axiomns into a fresh empty ontology.
      # Note that there is nothing stopping us stuffing them back
      # into the original asserted ontology if we wanted to do this.
      inferredOntology = DesenhadorOntologia( strNewPhysicalURI, strNewOntologyURI )
      inferredOntology.criar()
      # Now get the inferred ontology generator to generate some inferred axioms
      # for us (into our fresh ontology). Remember that we specified the reasoner that we want
      # to use and the inferred axiom generators that we want to use.
      iog.fillOntology( self.manager, inferredOntology.obterOntologia() )
      #inferredOntology.gravar()
      return inferredOntology
      


#______________________________________________________________________________
# Funcoes Utilitarias
def colectarInformacao( ontology ):
   visitor = OWLEntityCollector()
   # < ALTERAR: colocar o proximo argumento a True e analisar efeito >
   visitor.setCollectClasses( False )
   visitor.setCollectDataProperties( True )
   visitor.setCollectDataTypes( True )
   visitor.setCollectIndividuals( True )
   visitor.setCollectObjectProperties( True )
   toVisit = []
   toVisit += ontology.getClassAxioms()
   toVisit += ontology.getObjectPropertyAxioms()
   toVisit += ontology.getIndividualAxioms()
   toVisit += ontology.getLogicalAxioms() 
   #print toVisit
   for v in toVisit: visitor.visit( v )
   return visitor.getObjects()

